#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
服务管理器 - 协调所有服务模块
"""

import asyncio
import subprocess
import sys
import os
import threading
import time
from typing import Dict, Any, Optional
from contextlib import asynccontextmanager

from database_manager import DatabaseManager
from order_parser import OrderParser
from file_monitor_manager import FileMonitorManager
from websocket_manager import WebSocketManager

# Windows 窗口显示常量
SW_HIDE = 0
SW_SHOW = 5
CREATE_NO_WINDOW = 0x08000000
CREATE_NEW_CONSOLE = 0x00000010


class ServiceManager:
    """服务管理器"""
    
    def __init__(self, db_path: str = "orders.db"):
        # 初始化各个管理器
        self.db_manager = DatabaseManager(db_path)
        self.order_parser = OrderParser()
        self.file_monitor_manager = FileMonitorManager(self.db_manager, self.order_parser)
        self.websocket_manager = WebSocketManager(self.db_manager)
        
        # 设置状态变化回调
        self.file_monitor_manager.add_status_callback(self._on_order_status_change)
        # 设置订单更新回调
        self.file_monitor_manager.add_status_callback(self._on_order_updated)
        
        # 角标识别进程
        self.recognition_process = None
        self._recognition_monitor_thread: Optional[threading.Thread] = None
        self._keep_recognition_running = False
        self._recognition_restart_delay = 3  # seconds between restart attempts
        
        # 获取基础目录
        if getattr(sys, 'frozen', False):
            self.base_dir = os.path.dirname(sys.executable)
        else:
            self.base_dir = os.path.dirname(os.path.abspath(__file__))
        
        # 角标识别 exe 路径
        self.recognition_exe = os.path.join(self.base_dir, 'tools', '角标识别.exe')
    
    async def _on_order_status_change(self, order_number: str, status_data: dict):
        """订单状态变化回调"""
        print(f"🔄 服务管理器收到状态变化: 订单编号 {order_number}")
        print(f"📊 状态数据: {status_data}")
        
        # 检查是否是删除事件
        if status_data.get('action') == 'deleted':
            print(f"🗑️ 订单被删除: {status_data.get('number', '')} - {status_data.get('customer', '')}")
            # 广播订单删除事件
            await self.websocket_manager.broadcast_order_deleted(order_number, status_data)
        else:
            # 获取订单信息用于打印
            order = self.db_manager.find_order_by_number(order_number)
            if order:
                print(f"📋 订单信息: {order['number']} - {order['customer']}")
            
            # 广播订单状态变化
            await self.websocket_manager.broadcast_order_status_change(order_number, status_data)
    
    async def _on_order_updated(self, order_number: str, update_data: dict):
        """订单信息更新回调"""
        print(f"🔄 服务管理器收到订单更新: 订单编号 {order_number}")
        
        # 获取完整订单信息
        order = self.db_manager.find_order_by_number(order_number)
        if order:
            print(f"📋 更新后订单信息: {order['number']} - {order['customer']}")
            
            # 广播订单信息更新
            await self.websocket_manager.broadcast_order_updated(order_number, order)
        else:
            print(f"❌ 未找到订单: {order_number}")
    
    def start_services(self) -> bool:
        """启动所有服务"""
        try:
            self._keep_recognition_running = True
            # 启动角标识别进程
            self._start_recognition_process()
            
            # 启动队列处理器
            self.file_monitor_manager.start_queue_processor()
            
            # 启动文件监控
            success = self.file_monitor_manager.start_automatic_monitoring()
            if success:
                print("✅ 文件监控服务启动成功")
            else:
                print("❌ 文件监控服务启动失败")
                return False
            
            # 启动时进行全量扫描
            print("\n🔍 服务启动时进行全量扫描...")
            scan_results = self.file_monitor_manager.full_scan_current_date()
            print(f"✅ 全量扫描完成: 扫描了 {scan_results.get('total_dates_scanned', 0)} 个日期目录")
            
            # 启动时清理无效订单
            print("\n🧹 服务启动时清理无效订单...")
            cleanup_results = self.file_monitor_manager.cleanup_all_missing_orders()
            print(f"✅ 清理完成: 清理了 {cleanup_results.get('cleaned_count', 0)} 个无效订单")
            
            print("✅ 所有服务启动完成")
            return True
            
        except Exception as e:
            print(f"❌ 启动服务失败: {e}")
            return False
    
    def stop_services(self):
        """停止所有服务"""
        try:
            self._keep_recognition_running = False
            # 停止角标识别进程
            self._stop_recognition_process()
            
            # 停止文件监控
            self.file_monitor_manager.stop_monitoring()
            print("✅ 文件监控服务已停止")
            
            # 停止队列处理器
            self.file_monitor_manager.stop_queue_processor()
            print("✅ 队列处理器已停止")
            
            # 关闭WebSocket连接
            asyncio.create_task(self.websocket_manager.close_all_connections())
            print("✅ WebSocket服务已停止")
            
            print("✅ 所有服务已停止")
            
        except Exception as e:
            print(f"❌ 停止服务失败: {e}")
    
    def get_service_status(self) -> Dict[str, Any]:
        """获取服务状态"""
        return {
            "database": "connected",
            "file_monitoring": self.file_monitor_manager.get_monitoring_status(),
            "websocket_connections": self.websocket_manager.get_connection_count(),
            "statistics": self.db_manager.get_statistics()
        }
    
    def restart_monitoring(self) -> bool:
        """重启监控服务"""
        return self.file_monitor_manager.restart_monitoring()
    
    def full_scan_current_date(self) -> dict:
        """全量扫描当前日期目录"""
        return self.file_monitor_manager.full_scan_current_date()
    
    def cleanup_missing_orders(self) -> dict:
        """清理不存在的订单"""
        return self.file_monitor_manager.cleanup_all_missing_orders()
    
    def get_database_manager(self) -> DatabaseManager:
        """获取数据库管理器"""
        return self.db_manager
    
    def get_file_monitor_manager(self) -> FileMonitorManager:
        """获取文件监控管理器"""
        return self.file_monitor_manager
    
    def get_websocket_manager(self) -> WebSocketManager:
        """获取WebSocket管理器"""
        return self.websocket_manager
    
    def get_order_parser(self) -> OrderParser:
        """获取订单解析器"""
        return self.order_parser
    
    def _start_recognition_process(self):
        """启动角标识别进程"""
        try:
            # 如果已有进程在运行，直接返回
            if self.recognition_process and self.recognition_process.poll() is None:
                print(f"ℹ️ 角标识别进程已在运行 (PID: {self.recognition_process.pid})")
                return

            # 清理已退出的进程引用
            if self.recognition_process and self.recognition_process.poll() is not None:
                self.recognition_process = None

            # 检查 exe 是否存在
            if not os.path.exists(self.recognition_exe):
                print(f"⚠️ 角标识别程序不存在: {self.recognition_exe}")
                # 尝试创建 tools 目录并提示
                tools_dir = os.path.join(self.base_dir, 'tools')
                if not os.path.exists(tools_dir):
                    os.makedirs(tools_dir, exist_ok=True)
                    print(f"📁 已创建 tools 目录: {tools_dir}")
                print(f"💡 提示: 请将 角标识别.exe 放到 {tools_dir} 目录")
                self._keep_recognition_running = False
                return
            
            print(f"🚀 启动角标识别进程: {self.recognition_exe}")
            
            # 获取服务端当前监控的日期目录路径
            input_dir = self.file_monitor_manager.get_today_monitor_path()
            
            # 输出目录为输入目录下的 output 文件夹
            output_dir = os.path.join(input_dir, 'output')
            
            # 确保输入目录存在
            if not os.path.exists(input_dir):
                os.makedirs(input_dir, exist_ok=True)
                print(f"📁 已创建输入目录: {input_dir}")
            
            # 确保输出目录存在
            if not os.path.exists(output_dir):
                os.makedirs(output_dir, exist_ok=True)
                print(f"📁 已创建输出目录: {output_dir}")
            
            print(f"📂 输入目录（服务端监控目录）: {input_dir}")
            print(f"📂 输出目录: {output_dir}")
            
            # 检查依赖文件
            tools_dir = os.path.join(self.base_dir, 'tools')
            dependencies = {
                'orders.db': os.path.join(self.base_dir, 'orders.db'),
                'paddleocr模型': os.path.join(tools_dir, 'paddleocr'),
            }
            
            missing_deps = []
            for name, path in dependencies.items():
                if not os.path.exists(path):
                    missing_deps.append(f"  ❌ {name}: {path}")
            
            if missing_deps:
                print(f"⚠️ 警告：以下依赖文件缺失，可能导致角标识别进程启动失败：")
                for dep in missing_deps:
                    print(dep)
            
            # 构建命令行参数
            cmd_args = [self.recognition_exe]
            if input_dir:
                cmd_args.extend(['--input-dir', input_dir])
            if output_dir:
                cmd_args.extend(['--output-dir', output_dir])
            
            print(f"🔧 启动命令: {' '.join(cmd_args)}")
            
            # 检测是否为打包后的exe环境
            is_frozen = getattr(sys, 'frozen', False)
            
            if os.name == 'nt':  # Windows
                if is_frozen:
                    # 打包exe：隐藏命令行窗口
                    startupinfo = subprocess.STARTUPINFO()
                    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
                    startupinfo.wShowWindow = SW_HIDE
                    creation_flags = CREATE_NO_WINDOW
                    print(f"🔧 检测到exe环境，角标识别进程将在后台运行")
                    
                    # 以独立进程启动 exe，后台运行
                    self.recognition_process = subprocess.Popen(
                        cmd_args,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        startupinfo=startupinfo,
                        creationflags=creation_flags,
                        cwd=os.path.join(self.base_dir, 'tools')
                    )
                else:
                    # Python运行：显示命令行窗口（创建新的控制台）
                    creation_flags = CREATE_NEW_CONSOLE
                    print(f"🔧 检测到Python环境，角标识别进程将显示命令行")
                    
                    # 以独立进程启动 exe，显示命令行窗口
                    self.recognition_process = subprocess.Popen(
                        cmd_args,
                        creationflags=creation_flags,
                        cwd=os.path.join(self.base_dir, 'tools')
                    )
            else:
                # 非Windows系统
                self.recognition_process = subprocess.Popen(
                    cmd_args,
                    cwd=os.path.join(self.base_dir, 'tools')
                )
            
            # 根据环境显示不同的成功信息
            if is_frozen:
                print(f"✅ 角标识别进程已启动（后台运行，PID: {self.recognition_process.pid}）")
            else:
                print(f"✅ 角标识别进程已启动（显示命令行，PID: {self.recognition_process.pid}）")

            # 启动监控线程，保持进程稳定运行
            monitor_thread = threading.Thread(
                target=self._monitor_recognition_process,
                daemon=True
            )
            monitor_thread.start()
            self._recognition_monitor_thread = monitor_thread
            
        except Exception as e:
            print(f"❌ 启动角标识别进程失败: {e}")
            import traceback
            traceback.print_exc()
    
    def _monitor_recognition_process(self):
        """监控角标识别进程的输出和状态"""
        if not self.recognition_process:
            return
        
        restart_needed = False

        try:
            # 创建日志文件路径
            log_dir = os.path.join(self.base_dir, 'logs')
            os.makedirs(log_dir, exist_ok=True)
            log_file = os.path.join(log_dir, 'recognition_process.log')
            
            print(f"📝 角标识别进程日志: {log_file}")
            
            # 读取输出并写入日志
            with open(log_file, 'w', encoding='utf-8') as f:
                f.write(f"=== 角标识别进程启动 ===\n")
                f.write(f"PID: {self.recognition_process.pid}\n")
                f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
                f.write(f"=" * 50 + "\n\n")
                f.flush()
                
                # 读取标准输出
                restart_needed = False
                while True:
                    # 检查进程是否还在运行
                    return_code = self.recognition_process.poll()
                    
                    if return_code is not None:
                        # 进程已退出
                        f.write(f"\n{'=' * 50}\n")
                        f.write(f"进程已退出，退出码: {return_code}\n")
                        f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
                        f.flush()
                        
                        print(f"⚠️ 角标识别进程已退出 (退出码: {return_code})")
                        print(f"📝 详细日志请查看: {log_file}")
                        
                        if return_code != 0:
                            print(f"❌ 进程异常退出！")
                            # 尝试读取剩余的错误输出
                            if self.recognition_process.stderr:
                                stderr_output = self.recognition_process.stderr.read()
                                if stderr_output:
                                    stderr_text = stderr_output.decode('utf-8', errors='ignore')
                                    f.write(f"\n错误输出:\n{stderr_text}\n")
                                    print(f"❌ 错误信息: {stderr_text[:200]}")
                        restart_needed = self._keep_recognition_running
                        # 清理进程引用
                        self.recognition_process = None
                        break
                    
                    # 读取输出
                    if self.recognition_process.stdout:
                        line = self.recognition_process.stdout.readline()
                        if line:
                            line_text = line.decode('utf-8', errors='ignore')
                            f.write(line_text)
                            f.flush()
                            # 也打印重要信息
                            if '错误' in line_text or 'Error' in line_text or '失败' in line_text:
                                print(f"⚠️ 角标识别: {line_text.strip()}")
                    
                    time.sleep(0.1)
                    
        except Exception as e:
            print(f"❌ 监控角标识别进程时出错: {e}")
            import traceback
            traceback.print_exc()
        finally:
            if restart_needed:
                print(f"🔁 角标识别进程将在 {self._recognition_restart_delay} 秒后尝试重启")
                time.sleep(self._recognition_restart_delay)
                if self._keep_recognition_running:
                    try:
                        self._start_recognition_process()
                    except Exception as restart_error:
                        print(f"❌ 角标识别进程重启失败: {restart_error}")
                        import traceback
                        traceback.print_exc()
    
    def _stop_recognition_process(self):
        """停止角标识别进程"""
        try:
            if self.recognition_process:
                print(f"🛑 正在停止角标识别进程 (PID: {self.recognition_process.pid})...")
                
                # 尝试优雅地终止进程
                self.recognition_process.terminate()
                
                # 等待进程结束（最多5秒）
                try:
                    self.recognition_process.wait(timeout=5)
                    print("✅ 角标识别进程已停止")
                except subprocess.TimeoutExpired:
                    # 超时则强制结束
                    print("⚠️ 进程未响应，强制结束...")
                    self.recognition_process.kill()
                    self.recognition_process.wait()
                    print("✅ 角标识别进程已强制停止")
                
                self.recognition_process = None
            else:
                print("ℹ️ 角标识别进程未运行")
                
        except Exception as e:
            print(f"❌ 停止角标识别进程失败: {e}")
    
    @asynccontextmanager
    async def lifespan_context(self, app):
        """应用生命周期上下文管理器"""
        print("启动订单管理系统服务端...")
        
        # 启动服务
        if self.start_services():
            print("✅ 服务启动成功")
        else:
            print("❌ 服务启动失败")
        
        print("服务端启动完成，等待客户端连接...")
        
        yield
        
        # 关闭时清理
        print("正在关闭服务端...")
        self.stop_services()
        print("服务端已关闭")
